package gui;

import java.awt.BorderLayout;
import java.awt.ComponentOrientation;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;

import enums.Direction;

import listeners.newGameListener;

import application.GameManager;
import application.GameMatrix;
import application.snakes.Snake;
import application.snakes.SnakeFactory;
import application.auxclasses.Constant;
import application.auxclasses.myLock;
import application.food.FoodLocator;
/**
 * the main snake game frame.
 * fields:
 * _matrix is the logical aspect of the game matrix
 * _timer is the frame repaint and snake speed timer
 * _foodTimer is the timer for spawning new food on the matrix
 * _snake is the type of snake the player is using
 * _size is the size of the game matrix
 * _FoodLocator is the object which creates a new random food and adds it to
 * 		the matrix
 * _gamePanel is the actual game panel, where the snake and food types are
 * 		painted
 * _scoreLabel is a JLabel with "score:" text on it
 * _gameManager is the game manager class
 * _module key determines when we ignore the timer.
 * _counterKey is used with the modulo key to ignore timer, and thus control the speed of the snake.
 * _speedTimer is set up each time we change speed 
 *
 */
public class GameFrame extends JFrame implements ActionListener,KeyListener {

	private GameMatrix _matrix;
	private Timer _timer;
	private Timer _foodTimer;
	private Snake _snake;
	private int _size;
	private FoodLocator _FoodLocator;
	private GamePanel _gamePanel;
	private JLabel _scoreLabel;
	private JTextField _scoreText;
	private GameManager _gameManager;
	private int _moduloKey;
	private int _counterKey;
	private Timer _speedTimer;
	private myLock _myLock;

	public GameFrame(ImageIcon[] pictures,GameManager gameManager,String snake) {
		_size = 30;
		this._matrix = new GameMatrix(_size);
		this._gameManager = gameManager;
		this._snake = SnakeFactory.create(snake,this._matrix,gameManager);
		this._FoodLocator = new FoodLocator(this._matrix);
		this.addFood();
		this._gamePanel = new GamePanel(this._matrix,this._snake,pictures);
		this._moduloKey = 2;
		this._counterKey = 0;
		this._myLock = new myLock();
		this._timer = new Timer(50,this);
		this._speedTimer = new Timer(30000,this);
		_timer.start();
		int delay = 5000;
		_foodTimer = new Timer(delay,this);
		_foodTimer.start();
		this.getContentPane().setLayout(new BorderLayout());
		this._gamePanel.addKeyListener(this);
		this._gamePanel.setFocusable(true);
		this.getContentPane().add(this._gamePanel,BorderLayout.CENTER);
		JPanel tScorePanel = new JPanel();
		tScorePanel.setLayout(new FlowLayout());
		tScorePanel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
		this._scoreLabel = new JLabel("Score:");
		this._scoreText = new JTextField("0",10);
		this._scoreText.setEditable(false);
		JButton tStartNewGameButton = new JButton("Start New Game");
		tStartNewGameButton.addActionListener(new newGameListener(this._gameManager,this._snake));
		tScorePanel.add(this._scoreLabel);
		tScorePanel.add(this._scoreText);
		tScorePanel.add(tStartNewGameButton);
		this.getContentPane().add(tScorePanel,BorderLayout.SOUTH);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setSize(610, 630);
		this.setVisible(true);
		Constant.set_flag(true);
		GameManager.print("at end of game frame constructor flag is " + Constant.get_flag());
	}
	public void upFlags(){
		Constant.set_flag(true);
		synchronized (this._myLock) {
			this._myLock.set_flag(true);
		}
	}
	/**
	 * action for the repaint timer
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == _timer){
			
			this._counterKey = (this._counterKey + 1) % this._moduloKey;
			if(((this._counterKey % this._moduloKey) == 0)){
				this.upFlags();
				this._snake.move();
				this._gamePanel.repaint();
			}
		}
		else if(e.getSource() == this._speedTimer){
			this.setNoramlSpeed();
		}
		else if (e.getSource() == _foodTimer) {//painting food
			this.upFlags();
			this.addFood();
			this._snake.move();
			this._gamePanel.repaint();
		}
	}
	/**
	 * sets the snake movement speed to double normal speed
	 */
	public void speedUpSnake(){
		if(this._speedTimer.isRunning()){
			GameManager.print("trying to slow down to normal");
			if(this._moduloKey == 3)
				this.setNoramlSpeed();
		}
		else{
			GameManager.print("trying to speed up");
			this._moduloKey = 1;
			this._speedTimer.start();
		}
	}
	/**
	 * sets the snake movement speed to half normal speed
	 */
	public void slowDownSnake(){
		if(this._speedTimer.isRunning()){
			GameManager.print("trying to speed up to normal");
			if(this._moduloKey == 1)
				this.setNoramlSpeed();
		}
		else{
			GameManager.print("trying to slow down");
			this._moduloKey = 3;
			this._speedTimer.start();
		}
	}
	/**
	 * sets the snake movement speed to normal speed
	 */
	public void setNoramlSpeed(){
		this._speedTimer.stop();
		this._moduloKey = 2;
	}
	/**
	 * updates the score text label
	 */
	public void updateScore(){
		int score = this._snake.get_score();
		this._scoreText.setText(Integer.toString(score));
	}
	/**
	 * stops all timers when game ends
	 */
	public void stopTimers(){
		this._timer.stop();
		this._foodTimer.stop();
	}
	/**
	 * repaint game panel
	 */
	public void repaintPanel() {
		this._gamePanel.repaint();
	}
	/**
	 * getter
	 * @return
	 */
	public String getScore() {
		return this._scoreText.getText();
	}
	public void addFood() {
		this._FoodLocator.locateFoodOnBoard();
	}
	@Override
	public void keyPressed(KeyEvent e) {
		GameManager.print("The flag is " + Constant.get_flag());
		GameManager.print("Passed into KeyPressed!");
			synchronized (this._myLock) {//sync locked.
				if(this._myLock.is_flag()){//check semaphore
					this._myLock.set_flag(false);//down on Semaphore.
					if (e.getKeyCode() == KeyEvent.VK_LEFT){
						GameManager.print("going to change snake direction " + "left");
						this._snake.changeDirection(Direction.WEST);
					}
					if (e.getKeyCode() == KeyEvent.VK_RIGHT){
						GameManager.print("going to change snake direction " + "right");
						this._snake.changeDirection(Direction.EAST);
					}
					if (e.getKeyCode() == KeyEvent.VK_UP){
						GameManager.print("going to change snake direction " + "up");
						this._snake.changeDirection(Direction.NORTH);
					}
					if (e.getKeyCode() == KeyEvent.VK_DOWN){
						GameManager.print("going to change snake direction " + "down");
						this._snake.changeDirection(Direction.SOUTH);
					}
				}
				else{
					GameManager.print("Could not enter to change direction");
				}
			}
		//}	
	}
	@Override
	public void keyReleased(KeyEvent e) {
		GameManager.print("inside KEY_RELEASED");	
	}
	@Override
	public void keyTyped(KeyEvent e) {
		GameManager.print("inside KEY_TYPED");	
	}
}
